import ch.qos.logback.classic.Level;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.*;

public class ServerConfiguration {
    // 设置默认参数
    // 默认日志打印到控制台
    private final String default_log = "console";
    // 默认系统的日志级别为INFO
    private final Level default_log_level = Level.INFO;
    // 系统的PID文件
    private final String default_pid = "";
    // 是否用后台方式启动
    private final boolean defaultDaemonMode = false;

    private String   log;
    private Level    log_level;
    private String   pid;
    private boolean  daemonMode;

    public  String   mode = null;

    public  String   udp_host = null;
    public  int      udp_port = 0;

    public  String   tcp_host = null;
    public  int      tcp_port = 0;

    // 多网卡环境下，组播地址使用的本地接口信息
    public  String   udp_multicast_if = null;

    // UDP本地端口，避免回环问题
    public  int      udp_local_port = 0;
    public  int      filter_udp_port = 0;

    public HashMap<String, TcpTarget> tcpTargetList = new HashMap<>();

    public ServerConfiguration() throws ServerException
    {
        log = default_log;
        log_level = default_log_level;
        pid = default_pid;
        daemonMode = defaultDaemonMode;
    }

    // 读取参数配置文件
    public void loadConfigurationFile(String configurationFileName) throws ServerException {
        Properties appProperties = new Properties();
        File configurationFile;

        // 首先读取参数配置里头的信息
        if (configurationFileName != null)
        {
            configurationFile = new File(configurationFileName);
            try (InputStream input = new FileInputStream(configurationFile)) {
                // 加载属性文件
                appProperties.load(input);
            } catch (Exception ex) {
                throw new ServerException("Errors when load conf file [" + configurationFileName + "]", ex);
            }
        }

        // 加载配置信息，根据参数配置信息修改默认配置
        for (Map.Entry<Object, Object> entry : appProperties.entrySet()) {
            switch (entry.getKey().toString().toUpperCase()) {
                case "DAEMON" -> {
                    if (entry.getValue().toString().isEmpty()) {
                        daemonMode = this.defaultDaemonMode;
                    } else {
                        setDaemon(entry.getValue().toString());
                    }
                }
                case "LOG" -> {
                    if (entry.getValue().toString().isEmpty()) {
                        log = this.default_log;
                    } else {
                        setLog(entry.getValue().toString());
                    }
                }
                case "LOG_LEVEL" -> {
                    if (entry.getValue().toString().isEmpty()) {
                        log_level = this.default_log_level;
                    } else {
                        setLog_level(entry.getValue().toString());
                    }
                }
                case "PID" -> {
                    if (entry.getValue().toString().isEmpty()) {
                        pid = this.default_pid;
                    } else {
                        setPid(entry.getValue().toString());
                    }
                }
                case "MODE" -> {
                    if (entry.getValue().toString().equalsIgnoreCase("utot")) {
                        mode = "utot";
                    }
                    else if (entry.getValue().toString().equalsIgnoreCase("ttou")) {
                        mode = "ttou";
                    }
                    else
                    {
                        throw new ServerException("Unknown run mode [" + entry.getKey().toString() + "] in [" + configurationFileName + "].");
                    }
                }
                case "UDP_HOST" -> {
                    if (entry.getValue().toString().isEmpty()) {
                        udp_host = null;
                    } else {
                        setPid(entry.getValue().toString());
                    }
                }
                default ->
                {
                    if (entry.getKey().toString().toLowerCase().startsWith("tcp_host_")) {
                        String targetKey = entry.getKey().toString().toLowerCase().replace("tcp_host_", "");
                        this.setTcpTarget_host(targetKey, entry.getValue().toString().trim());
                    } else if (entry.getKey().toString().toLowerCase().startsWith("tcp_port_")) {
                        String targetKey = entry.getKey().toString().toLowerCase().replace("tcp_port_", "");
                        this.setTcpTarget_port(targetKey, entry.getValue().toString().trim());
                    }
                    throw new ServerException("Unknown configuration parameter [" + entry.getKey().toString() + "] in [" + configurationFileName + "].");
                }
            }
        }
    }

    public String getLog()
    {
        return log;
    }
    public Level getLog_level() { return log_level;}

    public String getPid() {return pid;}
    public boolean getDaemonMode()
    {
        return this.daemonMode;
    }

    public void setLog_level(String pLog_level) throws ServerException {
        log_level = Level.valueOf(pLog_level);

        if (!log_level.levelStr.equalsIgnoreCase(pLog_level))
        {
            // 如果LogLevel的参数有错误，设置内容将不会有效
            throw new ServerException("Bad log_level [" + pLog_level + "].");
        }
    }

    public void setLog(String pLog) { log = pLog.trim();}

    public void setDaemon(String pDaemonMode) throws ServerException {
        if (pDaemonMode.trim().equalsIgnoreCase("true"))
        {
            daemonMode = true;
        } else if (pDaemonMode.trim().equalsIgnoreCase("false"))
        {
            daemonMode = false;
        }
        else {
            throw new ServerException("Invalid daemon mode parameter. true/false only.");
        }
    }

    public void setPid(String pPid)
    {
        pid = pPid;
    }

    public void setUdp_host(String val)
    {
        udp_host = val;
    }

    public void setTcp_host(String val)
    {
        tcp_host = val;
    }

    public void setUdp_port(int val)
    {
        udp_port = val;
    }

    public void setTcp_port(int val)
    {
        tcp_port = val;
    }

    public void setUdp_port(String val)
    {
        int temp_UdpPort;
        try {
            temp_UdpPort = Integer.parseInt(val);
        }
        catch (NumberFormatException ignored)
        {
            throw new ServerException("Invalid parameter udp_port [" + val + "]. Must be a number.");
        }
        setUdp_port(temp_UdpPort);
    }

    public void setTcp_port(String val)
    {
        int temp_TcpPort;
        try {
            temp_TcpPort = Integer.parseInt(val);
        }
        catch (NumberFormatException ignored)
        {
            throw new ServerException("Invalid parameter tcp_port [" + val + "]. Must be a number.");
        }
        setTcp_port(temp_TcpPort);
    }

    public void setTcpTarget_host(String key, String val)
    {
        TcpTarget tcpTarget;
        if (this.tcpTargetList.containsKey(key))
        {
            tcpTarget = this.tcpTargetList.get(key);
        }
        else
        {
            tcpTarget = new TcpTarget();
        }
        tcpTarget.tcp_host = val;
        this.tcpTargetList.put(key, tcpTarget);
    }

    public void setTcpTarget_port(String key, int val)
    {
        TcpTarget tcpTarget;
        if (this.tcpTargetList.containsKey(key))
        {
            tcpTarget = this.tcpTargetList.get(key);
        }
        else
        {
            tcpTarget = new TcpTarget();
        }
        tcpTarget.tcp_port = val;
        this.tcpTargetList.put(key, tcpTarget);
    }

    public void setTcpTarget_port(String key, String val)
    {
        int temp_TcpPort;
        try {
            temp_TcpPort = Integer.parseInt(val);
        }
        catch (NumberFormatException ignored)
        {
            throw new ServerException("Invalid parameter tcp_port [" + val + "]. Must be a number.");
        }
        setTcpTarget_port(key, temp_TcpPort);
    }

    public String getMode()
    {
        return mode;
    }

    public void setMode(String val)
    {
        mode = val;
    }

    public String getUdp_multicast_if()
    {
        return udp_multicast_if;
    }

    public void setUdp_multicast_if(String val)
    {
        udp_multicast_if = val;
    }

    public void setUdp_local_port(int val)
    {
        this.udp_local_port = val;
    }

    public void setUdp_local_port(String val)
    {
        int temp_UdpLocalPort;
        try {
            temp_UdpLocalPort = Integer.parseInt(val);
        }
        catch (NumberFormatException ignored)
        {
            throw new ServerException("Invalid parameter udp_local_port [" + val + "]. Must be a number.");
        }
        setUdp_local_port(temp_UdpLocalPort);
    }

    public void setFilter_udp_port(int val)
    {
        this.filter_udp_port = val;
    }

    public void setFilter_udp_port(String val)
    {
        int temp_UdpLocalPort;
        try {
            temp_UdpLocalPort = Integer.parseInt(val);
        }
        catch (NumberFormatException ignored)
        {
            throw new ServerException("Invalid parameter filter_udp_port [" + val + "]. Must be a number.");
        }
        setFilter_udp_port(temp_UdpLocalPort);
    }
}

